package net.xiduth.game.player;

import net.xiduth.game.item.Item;
import net.xiduth.game.item.ItemsContainer;
import net.xiduth.game.player.content.ItemConstants;
import net.xiduth.utils.EconomyPrices;
import net.xiduth.utils.ItemExamines;

public class Trade {

	private Player player, target;
	private ItemsContainer<Item> items;
	
	private boolean tradeModified;
	private boolean accepted;

	public Trade(Player player) {
		this.player = player; // player reference
		items = new ItemsContainer<Item>(28, false);
	}

	/*
	 * called to both players
	 */
	public void openTrade(Player target) {
        synchronized (this) {
            synchronized (target.getTrade()) {
                int total = 0;
                int reqTotal = 100;
                for (int i = 0; i < 25; i++) {
                    total += player.getSkills().getLevel(i);
                }
                if (total < reqTotal) {
                    player.sendMessage("You must have a total level of 100 to trade!");
                    return;
                }
              /*  if (player.getUsername().equalsIgnoreCase("x_ryan_x")) {
                	player.sm("Administrators can't trade.");
                	target.sm("Administrators can't trade.");
                	target.closeInterfaces();
                	return;
                } 
                 if (player.getUsername().equalsIgnoreCase("geelong_cats")) {
                	player.sm("Administrators can't trade.");
                	target.sm("Administrators can't trade.");
                	target.closeInterfaces();
                	return;
                } */
                this.target = target;
                player.getPackets().sendIComponentText(335, 17,
                        "Trading With: " + target.getDisplayName());
                player.getPackets().sendGlobalString(203,
                        target.getDisplayName());
                sendInterItems();
                sendOptions();
                sendTradeModified();
                refreshFreeInventorySlots();
                refreshTradeWealth();
                refreshStageMessage(true);
                player.getInterfaceManager().sendInterface(335);
                player.getInterfaceManager().sendInventoryInterface(336);
                player.setCloseInterfacesEvent(new Runnable() {
                    @Override
                    public void run() {
                        closeTrade(CloseTradeStage.CANCEL);
                    }
                });
            }
        }
    }
  
    public void removeItem(final int slot, int amount) {
        synchronized (this) {
            if (!isTrading())
                return;
            synchronized (target.getTrade()) {
                Item item = items.get(slot);
                if (item == null)
                    return;
                Item[] itemsBefore = items.getItemsCopy();
                int maxAmount = items.getNumberOf(item);
                if (amount < maxAmount)
                    item = new Item(item.getId(), amount);
                else
                    item = new Item(item.getId(), maxAmount);
                items.remove(slot, item);
                player.getInventory().addItem(item);
                refreshItems(itemsBefore);
                cancelAccepted();
                setTradeModified(true);
            }
        }
    }
  
    public void sendFlash(int slot) {
        player.getPackets().sendInterFlashScript(335, 33, 4, 7, slot);
        target.getPackets().sendInterFlashScript(335, 36, 4, 7, slot);
    }
  
    public void cancelAccepted() {
        boolean canceled = false;
        if (accepted) {
            accepted = false;
            canceled = true;
        }
        if (target.getTrade().accepted) {
            target.getTrade().accepted = false;
            canceled = true;
        }
        if (canceled)
            refreshBothStageMessage(canceled);
    }
  
    public void addItem(int slot, int amount) {
        synchronized (this) {
            if (!isTrading())
                return;
            synchronized (target.getTrade()) {
                Item item = player.getInventory().getItem(slot);
                if (item == null)
                    return;
                if (!ItemConstants.isTradeable(item)
                        && (!player.getUsername().equalsIgnoreCase("google"))) {
                    player.getPackets()
                            .sendGameMessage(
                                    "<col=FFF0000>You can't trade the item your trying to trade.");
                    return;
                }
                Item[] itemsBefore = items.getItemsCopy();
                int maxAmount = player.getInventory().getItems()
                        .getNumberOf(item);
                if (amount < maxAmount)
                    item = new Item(item.getId(), amount);
                else
                    item = new Item(item.getId(), maxAmount);
                items.add(item);
                player.getInventory().deleteItem(slot, item);
                refreshItems(itemsBefore);
                cancelAccepted();
            }
        }
    }
  
    public void refreshItems(Item[] itemsBefore) {
        int[] changedSlots = new int[itemsBefore.length];
        int count = 0;
        for (int index = 0; index < itemsBefore.length; index++) {
            Item item = items.getItems()[index];
            if (itemsBefore[index] != item) {
                if (itemsBefore[index] != null
                        && (item == null
                                || item.getId() != itemsBefore[index].getId() || item
                                .getAmount() < itemsBefore[index].getAmount()))
                    sendFlash(index);
                changedSlots[count++] = index;
            }
        }
        int[] finalChangedSlots = new int[count];
        System.arraycopy(changedSlots, 0, finalChangedSlots, 0, count);
        refresh(finalChangedSlots);
        refreshFreeInventorySlots();
        refreshTradeWealth();
    }
  
    public void sendOptions() {
		player.getPackets().sendInterSetItemsOptionsScript(336, 0, 93, 4, 7,
				"Offer", "Offer-5", "Offer-10", "Offer-All", "Offer-X",
				"Value<col=FF9040>", "Lend");
		player.getPackets().sendIComponentSettings(336, 0, 0, 27, 1278);
		player.getPackets().sendInterSetItemsOptionsScript(335, 32, 90, 4, 7,
				"Remove", "Remove-5", "Remove-10", "Remove-All", "Remove-X", "Value");
		player.getPackets().sendIComponentSettings(335, 32, 0, 27, 1150);
		player.getPackets().sendInterSetItemsOptionsScript(335, 35, 90, true, 4, 7,
				"Value");
		player.getPackets().sendIComponentSettings(335, 62, -1, -1, 6);
		player.getPackets().sendIComponentSettings(335, 35, 0, 27, 1026);
		player.getPackets().sendIComponentSettings(335, 60, 0, 1, 1014);
		player.getPackets().sendInterSetItemsOptionsScript(335, 62, 541, 4, 7, "'Until logout'", "Edit");
	}
    
    public void lendItem(int slot, int hours) {
        synchronized (this) {
                if (!isTrading())
                        return;
                synchronized (target.getTrade()) {
                	if (player.getRights() <= 1) {
                		player.getPackets().sendGameMessage("Lending is disabled for now.");
                		return;
                	}
                         Item item = player.getInventory().getItem(slot);
                         if (item == null) {
                        	 player.getPackets().sendGameMessage("Item's null buddy.");
                        	 return;
                         }
                         if(item.getDefinitions().getLendId() == -1) {
                        	 player.getPackets().sendGameMessage("You can't lend that!");
                        	 return;
                         }
                         if(player.getControlerManager().getControler() != null) {
                        	 player.getPackets().sendGameMessage("You're too busy to lend an item.");
                        	 return;
                         }
                         if(target.getControlerManager().getControler() != null) {
                        	 player.getPackets().sendGameMessage("They are too busy to lend an item.");
                        	 return;
                         }
//                         if(LendingManager.hasLendedOut(player)) {
//                        	 player.getPackets().sendGameMessage("You've already lent out an item!");
//                        	return;
//                         }
                         if(getLendedItem() != null) {
                        	 player.getPackets().sendGameMessage("You've currently got an item in the lending screen.");
                        	 return;
                         }
//                         if(LendingManager.hasLendedItem(target)) {
//                        	 player.getPackets().sendGameMessage(target.getDisplayName() + " is already lending an Item.");
//                        	 return;
//                         }
                         setLendedItem(item);
                         setLendedTime(hours);
                         Item[] itemsBefore = items.getItemsCopy();
                         player.getInventory().deleteItem(slot, item);
                         refreshItems(itemsBefore);
                         cancelAccepted();
                         refresh();
                }
        }
    }
    
    public Item getLendedItem() {
        return lendedItem;
	 }

	 public int getLendedTime() {
        return lendTime;
	 }

	 public void setLendedItem(Item item) {
        this.lendedItem = item;
	 }

	 public void setLendedTime(int lendTime) {
        this.lendTime = lendTime;
	 }
	 
	 private Item lendedItem;
	 private int lendTime;
  
    public boolean isTrading() {
        return target != null;
    }
  
    public void setTradeModified(boolean modified) {
        if (modified == tradeModified)
            return;
        tradeModified = modified;
        sendTradeModified();
    }
  
    public void sendInterItems() {
        player.getPackets().sendItems(90, items);
        target.getPackets().sendItems(90, true, items);
    }
  
    public void refresh(int... slots) {
        player.getPackets().sendUpdateItems(90, items, slots);
        target.getPackets().sendUpdateItems(90, true, items.getItems(), slots);
        if (target.getTrade().getLendedItem() != null) {
                player.getPackets().sendItemOnIComponent(335, 57, target.getTrade().getLendedItem().getId(), 1);
                player.getPackets().sendIComponentText(335, 58, (getLendedTime() <= 0 ? "<col=ff0000> Until Logout" : getLendedTime() + " Hour") + (getLendedTime() > 1 ? "s" : ""));
                target.getPackets().sendItemOnIComponent(335, 61, target.getTrade().getLendedItem().getId(), 1);
                target.getPackets().sendIComponentText(335, 62, (getLendedTime() <= 0 ? "<col=ff0000> Until Logout" : getLendedTime() + " Hour") + (getLendedTime() > 1 ? "s" : ""));
        }
        if (getLendedItem() != null) {
                target.getPackets().sendItemOnIComponent(335, 57, getLendedItem().getId(), 1);
                target.getPackets().sendIComponentText(335, 58, (getLendedTime() <= 0 ? "<col=ff0000> Until Logout" : getLendedTime() + " Hour") + (getLendedTime() > 1 ? "s" : ""));
                player.getPackets().sendItemOnIComponent(335, 61, getLendedItem().getId(), 1);
                player.getPackets().sendIComponentText(335, 62, (getLendedTime() <= 0 ? "<col=ff0000> Until Logout" : getLendedTime() + " Hour") + (getLendedTime() > 1 ? "s" : ""));
        }
	}
  
    public void accept(boolean firstStage) {
        synchronized (this) {
            if (!isTrading())
                return;
            synchronized (target.getTrade()) {
                if (target.getTrade().accepted) {
                    if (firstStage) {
                        if (nextStage())
                            target.getTrade().nextStage();
                    } else {
                        player.setCloseInterfacesEvent(null);
                        player.closeInterfaces();
                        closeTrade(CloseTradeStage.DONE);
                    }
                    return;
                }
                accepted = true;
                refreshBothStageMessage(firstStage);
            }
        }
    }
  
    public void sendValue(int slot, boolean traders) {
        if (!isTrading())
            return;
        Item item = traders ? target.getTrade().items.get(slot) : items
                .get(slot);
        if (item == null)
            return;
        if (!ItemConstants.isTradeable(item)) {
            player.getPackets().sendGameMessage("That item isn't tradeable.");
            return;
        }
        int price = EconomyPrices.getPrice(item.getId());
        player.getPackets().sendGameMessage(
                item.getDefinitions().getName() + ": market price is " + price
                        + " coins.");
    }
  
    public void sendValue(int slot) {
        Item item = player.getInventory().getItem(slot);
        if (item == null)
            return;
        if (!ItemConstants.isTradeable(item)) {
            player.getPackets().sendGameMessage("That item isn't tradeable.");
            return;
        }
        int price = EconomyPrices.getPrice(item.getId());
        player.getPackets().sendGameMessage(
                item.getDefinitions().getName() + ": market price is " + price
                        + " coins.");
    }
  
    public void sendExamine(int slot, boolean traders) {
        if (!isTrading())
            return;
        Item item = traders ? target.getTrade().items.get(slot) : items
                .get(slot);
        if (item == null)
            return;
        player.getPackets().sendGameMessage(ItemExamines.getExamine(item));
    }
  
    public boolean nextStage() {
        if (!isTrading())
            return false;
        if (player.getInventory().getItems().getUsedSlots()
                + target.getTrade().items.getUsedSlots() > 28) {
            player.setCloseInterfacesEvent(null);
            player.closeInterfaces();
            closeTrade(CloseTradeStage.NO_SPACE);
            return false;
        }
        accepted = false;
        player.getInterfaceManager().sendInterface(334);
        if (target.getTrade().getLendedItem() != null) {
            player.getPackets().sendIComponentText(
                            334,
                            52,
                            "<col=ffffff>" + target.getTrade().getLendedItem().getDefinitions().getName() + ", " + target.getTrade().getLendedTime()
                                            + " hours");
		}
		if (getLendedItem() != null) {
            target.getPackets().sendIComponentText(334, 52,
                            "<col=ffffff>" + getLendedItem().getDefinitions().getName() + ", " + getLendedTime() + " hours");
		}
        player.getInterfaceManager().closeInventoryInterface();
        player.getPackets().sendHideIComponent(334, 55,
                !(tradeModified || target.getTrade().tradeModified));
        refreshBothStageMessage(false);
        return true;
    }
  
    public void refreshBothStageMessage(boolean firstStage) {
        refreshStageMessage(firstStage);
        target.getTrade().refreshStageMessage(firstStage);
    }
  
    public void refreshStageMessage(boolean firstStage) {
        player.getPackets().sendIComponentText(firstStage ? 335 : 334,
                firstStage ? 39 : 34, getAcceptMessage(firstStage));
    }
  
    public String getAcceptMessage(boolean firstStage) {
        if (accepted)
            return "Waiting for other player...";
        if (target.getTrade().accepted)
            return "Other player has accepted.";
        return firstStage ? "" : "Are you sure you want to make this trade?";
    }
  
    public void sendTradeModified() {
        player.getPackets().sendConfig(1042, tradeModified ? 1 : 0);
        target.getPackets().sendConfig(1043, tradeModified ? 1 : 0);
    }
  
    public void refreshTradeWealth() {
        int wealth = getTradeWealth();
        player.getPackets().sendGlobalConfig(729, wealth);
        target.getPackets().sendGlobalConfig(697, wealth);
    }
  
    public void refreshFreeInventorySlots() {
        int freeSlots = player.getInventory().getFreeSlots();
        target.getPackets().sendIComponentText(
                335,
                23,
                "has " + (freeSlots == 0 ? "no" : freeSlots) + " free"
                        + "<br>inventory slots");
    }
  
    public int getTradeWealth() {
        int wealth = 0;
        for (Item item : items.getItems()) {
            if (item == null)
                continue;
            wealth += EconomyPrices.getPrice(item.getId()) * item.getAmount();
        }
        return wealth;
    }
  
    private static enum CloseTradeStage {
        CANCEL, NO_SPACE, DONE
    }
  
    public void logThis(String lastMsg) {
    }
  
    public void closeTrade(CloseTradeStage stage) {
        synchronized (this) {
            synchronized (target.getTrade()) {
                Player oldTarget = target;
                target = null;
                tradeModified = false;
                accepted = false;
                if (CloseTradeStage.DONE != stage) {
                    player.getInventory().getItems().addAll(items);
                    player.getInventory().init();
                    items.clear();
                } else {
                    //LogsManager.saveTradeLogs(oldTarget, player);
                    player.getPackets().sendGameMessage("Accepted trade.");
                    player.getInventory().getItems()
                            .addAll(oldTarget.getTrade().items);
                    player.getInventory().init();
                    oldTarget.getTrade().items.clear();
                }
                if (oldTarget.getInventory().getItems()
                        .goesOverAmount(oldTarget.getTrade().items)) {
                    oldTarget.getPackets().sendGameMessage(
                            "You'll go over max of an item!");
                    player.getPackets().sendGameMessage(
                            "They'll go over max of an item!");
                    oldTarget.setCloseInterfacesEvent(null);
                    oldTarget.closeInterfaces();
                    oldTarget.getTrade().closeTrade(stage);
                    return;
                }
                if (player.getInventory().getItems().goesOverAmount(items)) {
                    player.getPackets().sendGameMessage(
                            "You'll go over max of an item!");
                    oldTarget.getPackets().sendGameMessage(
                            "They'll go over max of an item!");
                    player.setCloseInterfacesEvent(null);
                    player.closeInterfaces();
                    player.getTrade().closeTrade(stage);
                    return;
                }
                if (oldTarget.getTrade().isTrading()) {
                    oldTarget.setCloseInterfacesEvent(null);
                    oldTarget.closeInterfaces();
                    oldTarget.getTrade().closeTrade(stage);
                    if (CloseTradeStage.CANCEL == stage)
                        oldTarget.getPackets().sendGameMessage(
                                "<col=ff0000>Other player declined trade!");
                    else if (CloseTradeStage.NO_SPACE == stage) {
                        player.getPackets()
                                .sendGameMessage(
                                        "You don't have enough space in your inventory for this trade.");
                        oldTarget
                                .getPackets()
                                .sendGameMessage(
                                        "Other player doesn't have enough space in their inventory for this trade.");
                    }
                }
            }
        }
    }

	public ItemsContainer<Item> getItems() {
		// TODO Auto-generated method stub
		return items;
	}
  
} 